import { ref, watch, onUnmounted } from 'vue'

export function useDebounce<T extends (...args: any[]) => any>(
  fn: T,
  delay: number = 300
): [(...args: Parameters<T>) => void, () => void] {
  let timeoutId: NodeJS.Timeout | null = null

  const debouncedFn = (...args: Parameters<T>) => {
    if (timeoutId) {
      clearTimeout(timeoutId)
    }
    timeoutId = setTimeout(() => {
      fn(...args)
    }, delay)
  }

  const cancel = () => {
    if (timeoutId) {
      clearTimeout(timeoutId)
      timeoutId = null
    }
  }

  onUnmounted(() => {
    cancel()
  })

  return [debouncedFn, cancel]
}

export function useThrottle<T extends (...args: any[]) => any>(
  fn: T,
  delay: number = 300
): [(...args: Parameters<T>) => void, () => void] {
  let timeoutId: NodeJS.Timeout | null = null
  let lastExecTime = 0

  const throttledFn = (...args: Parameters<T>) => {
    const currentTime = Date.now()

    if (currentTime - lastExecTime > delay) {
      fn(...args)
      lastExecTime = currentTime
    } else if (!timeoutId) {
      timeoutId = setTimeout(() => {
        fn(...args)
        lastExecTime = Date.now()
        timeoutId = null
      }, delay - (currentTime - lastExecTime))
    }
  }

  const cancel = () => {
    if (timeoutId) {
      clearTimeout(timeoutId)
      timeoutId = null
    }
  }

  onUnmounted(() => {
    cancel()
  })

  return [throttledFn, cancel]
}

export function useDebouncedRef<T>(
  value: T,
  delay: number = 300
) {
  const debouncedValue = ref<T>(value)
  const [debouncedUpdate] = useDebounce((newValue: T) => {
    debouncedValue.value = newValue
  }, delay)

  watch(() => value, debouncedUpdate, { immediate: true })

  return debouncedValue
}

export function useThrottledRef<T>(
  value: T,
  delay: number = 300
) {
  const throttledValue = ref<T>(value)
  const [throttledUpdate] = useThrottle((newValue: T) => {
    throttledValue.value = newValue
  }, delay)

  watch(() => value, throttledUpdate, { immediate: true })

  return throttledValue
}

// 搜索防抖 Hook
export function useSearchDebounce(
  searchFn: (query: string) => void,
  delay: number = 500
) {
  const searchQuery = ref('')
  const isSearching = ref(false)

  const [debouncedSearch] = useDebounce(async (query: string) => {
    if (!query.trim()) {
      isSearching.value = false
      return
    }
    
    isSearching.value = true
    try {
      await searchFn(query)
    } finally {
      isSearching.value = false
    }
  }, delay)

  watch(searchQuery, (newQuery) => {
    debouncedSearch(newQuery)
  })

  return {
    searchQuery,
    isSearching
  }
}

// 滚动节流 Hook
export function useScrollThrottle(
  scrollFn: (event: Event) => void,
  delay: number = 100
) {
  const [throttledScroll] = useThrottle(scrollFn, delay)

  const addScrollListener = (element: HTMLElement | Window = window) => {
    element.addEventListener('scroll', throttledScroll)
  }

  const removeScrollListener = (element: HTMLElement | Window = window) => {
    element.removeEventListener('scroll', throttledScroll)
  }

  onUnmounted(() => {
    removeScrollListener()
  })

  return {
    addScrollListener,
    removeScrollListener
  }
}

// 窗口大小变化节流 Hook
export function useResizeThrottle(
  resizeFn: (event: Event) => void,
  delay: number = 200
) {
  const [throttledResize] = useThrottle(resizeFn, delay)

  const addResizeListener = () => {
    window.addEventListener('resize', throttledResize)
  }

  const removeResizeListener = () => {
    window.removeEventListener('resize', throttledResize)
  }

  onUnmounted(() => {
    removeResizeListener()
  })

  return {
    addResizeListener,
    removeResizeListener
  }
}